생각)
시그널은 인터럽트가 발생시 커널에서 프로세스를 처리하기 위해 사용하는 도구이며,
시그널을 직접 사용시 시스템콜로 볼 수도 있다.—> 커널이 인터럽트를 발생시킬때(context switching, 외부 인터럽트)에서는
시그널을 이용하지 않음. 커널이 직접 제어하는 걸로 보임!
인터럽트가 발생후 커널모드로 변환 후, 다시 사용자 모드로 변환할 때마다 커널모드에서 마지막으로 시그널 상태를 확인, 필요시 변경!
시그널은 다른 IPC 기법처럼 직접적으로 메세지를 전달하는 것이 아닌, 해당 프로세스에 정의된 시그널을 이용해서 통신한다.
커널은 따로 시그널을 사용하지 않는다. 시그널은 사용자가 프로세스를 제어하기 위해 운영체제에서 제공하는 시스템콜로 보임
시그널(Signal) <signal.h>
유닉스에서 30년 이상 사용된 전통된 기법
커널 또는 프로세스에서 다른 프로세스에 어떤 이벤트가 발생되었는지 알려주는 기법
ex) ctrl+c -프로세스 종료(시그널이 OS를 통해 프로세스로 전달, 프로세스에 정의된대로 시그널 수행)
시그널은 IPC 이상의 의미를 가지고 있다.
주요 시그널시그널 종류와 각 시그널에 따른 기본 동작이 미리 정해져 있다.
SIGKILL: 슈퍼관리자가 사용하는 시그널로, 프로세는 어떤 경우든 죽도록 되어 있다.
SIGALARM: 알람발생
SIGSTP: 프로세스를 멈춰라(ctrl+z)
SIGCONT: 멈춰진 프로세스를 실행하라
SIGINT: 프로세스에 인터럽트를 보내서 프로세스를 죽여라(ctrl+c)
SIGSEGV: 프로세스가 다른 메모리 영역을 침범했다.
시그널 명령 OS-Process & Scheduler-IPC trick(Signal & Socket) 참고
$kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
SIGUSR1, SIGUSR2를 이용해서 재정의를 많이 함-프로세스간의 통신에 사용(IPC)
시그널(signal) 동작프로그램에서 특정 시그널의 기본 동작 대신 다른 동작을 하도록 구현 가능
각 프로세스에서 시그널 처리에 대해 다음과 같은 동작 설정 가능
1. 시그널 무시
2. 시그널 블록(블록을 푸는 순간, 해당 프로세스에서 시그널 처리)
3. 프로그램 안에 등록된 시그널 핸들러로 재정의한 특정 동작 수행
4. 등록된 시그널 핸들러가 없다면, 커널에서 기본 동작 수행
시그널 보내기
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
받은 시그널에 따른 동작 정의
handler_t *signal(int signum, handler_t *handler);
void (*signal(int signum, void (*handler)(int)))(int);
signal(SIGINT, SIG_IGN);
signal(SIGINT, (void*)signal_handler);
SIG DFL은 재정의한 함수를 다시 default로 만들기 위해 사용
signal_loop.c
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static void signal_handler(int signo){
printf("Catch SIGINT!, but no stop\n");
}
int main(void){
if(signal(SIGINT, signal_handler)==SIG_ERR){
printf("Can't catch SIGINT!\n");
exit(1);
}
for(;;)pause();
return 0;
}
sigkill.c
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv){
int pid, result;
int sig_num;
if(argc!=3){
printf("usage %s [pid] [signum]\n", argv[0]);
exit(1);
}
pid=atoi(argv[1]);
sig_num=atoi(argv[2]);
result=kill(pid, sig_num);
if(result<0){
perror("To send Signal is failed\n");
exit(1);
}
return 0
}
celina@ubuntuserver:~/celina/IPC_test$ ./signal_loop
^CCatch SIGINT!, but no stop
^Z
[1]+ Stopped ./signal_loop
celina@ubuntuserver:~/celina/IPC_test$ ./signal_loop &
[2] 2233
celina@ubuntuserver:~/celina/IPC_test$ ./sigkill 2233 2
Catch SIGINT!, but no stop
시그널과 프로세스 (LINUX)PCB에 해당 프로세스가 블록 또는 처리해야하는 시그널 관력 정보 관리
커널 모드에서 사용자 모드 전환시 시그널 정보 확인해서, 해당 처리-커널 사용자 모드 전환시마다 시그널 확인
pending: 처리를 대기중인 시그널
sigpending
blocked: [64bit]-시그널개수: 1로 된 시그널은 blocked(sigpending과 blocked된 시그널 관리)
sig: 각각의 시그널에 대한 동작 정의
- 헤더 파일 <sys/types.h>, <signal.h>
- 함수 원형 : int kill(pid_t pid, int sig)
- 첫번째 파라미터 pid : 시그널을 받을 프로세스의 id.
- 두번째 파리미터 sig : pid로 지정된 프로세스에 보내려는 시그널.
- pid > 0 인 경우에는 pid로 지정한 프로세스에게 시그널을 보낸다.
- 헤더 파일 <signal.h>
- 함수 원형 : int raise(int sig)
- 파라미터 sig : 보내려는 시그널
- raise는 이 함수를 호출한 프로세스에게 인자로 지정한 시그널(sig)를 보낸다.
- signal handler가 호출되면 signal handler의 수행이 끝날 때 까지 raise 함수는 리턴하지 않는다.
- 헤더 파일 <sidlib.h>
- 함수 원형 : void abort(void)
- 이 함수를 호출한 프로세스에 SIGABRT 시그널을 보낸다.
- SIGABRT 시그널은 프로세스를 비정상적으로 종료시키고 코어 덤프 파일 생성.
- 헤더 파일 <signal.h>
- 함수 원형 : int sigsend(idtype_t idtype, id_t id, int sig)
- sig로 지정한 시그널을 id로 지정한 프로세스나 프로세스 그룹에 보낸다.